package com.google.code.netcheckin.util;

import com.google.code.netcheckin.io.Ascii;

public class ByteUtils {


		/** 
		  * Does the value of want occur at the given offset
		  * in data?
		  *
		*/

	public static final boolean areValuesAt(final byte[] want,
				final byte[] data, int offset) {
		final int ceil = want.length;
		if (want.length == 0 
			|| data.length == 0
			|| (offset + ceil) > data.length) {
			return false;	// want longer than remaining bytes
		}
		for (int idx = 0; idx < ceil; idx ++) {
			if(want[idx] != data[offset]) {
				return false;
			}
			offset ++;
		}
		return true;
	}

		/**
		  * Does data begin with the array given?
		  *
		*/

	public static final boolean beginsWith(final byte[] want, 
					final byte[] data) {
		return areValuesAt(want, data, 0);
	}


	public static final int copyInto(final byte[] dest, 
		final int destoffset, byte[] src) {
		return copyInto(dest, destoffset, src, 0, src.length);
	}
			
		/**
		  * Copy bytes from a source to a destination.
		  *
		*/

	public static final int copyInto(final byte[] dest,
		final int destoffset, byte[] src, int srcoffset, int srcend) {
		int answer = destoffset;
		for (int idx = srcoffset; idx < srcend; idx ++) {
			dest[answer] = src[idx];
			answer ++;
		}
		return answer;
	}

		/**
		  * Copy a fixed number of bytes from source to dest.
		  * Copy no more than destlength bytes. If the lenght of
		  * the source is shorter than the fixed length, the destination
		  * will be padded with spaces.
		  * @return offset of next available byte in dest.
		  *
		*/

	public static final int copyIntoFixedPadded(final byte[] dest,
		final int destoffset, final int destlength, final byte[] src) {
		int answer = destoffset;
		final int ceil = Math.min(src.length, destlength);
		int idx = 0;
		for (idx = 0; idx < ceil; idx ++) {
			dest[answer] = src[idx];
			answer ++;
		}
		final int padto = destoffset + destlength;
		while (answer < padto) {
			dest[answer] = Ascii.V_SPACE;
			answer ++;
			idx ++;
		}
		return answer;
	}

		/**
		  * Does data end with the array given?
		  *
		*/

	public static final boolean endsWith(final byte[] want, 
					final byte[] data) {
		return areValuesAt(want, data, data.length - want.length);
	}

		/**
		  * Find the location of "want" in data. Returns -1 if
		  * not present.
		  *
		*/

	public static final int indexOfIn(final byte want, final byte[] data){
		final int ceil = data.length;
		for (int idx = 0; idx < ceil; idx ++) {
			if (want == data[idx]) {
				return idx;
			}
		}
		return -1;
	}

		/**
		  * Find the location of "want" in data. Returns -1 if
		  * not present.
		  *
		*/

	public static final int indexOfIn(final byte[] want, final byte[] data){
		return indexOfIn(want, data, 0);
	}

		/**
		  * Find the location of "want" in data, beginning at
		  * the given offset. Returns -1 if not present.
		  * Minimum positive result is offset.
		  *
		*/

	public static final int indexOfIn(final byte[] want, final byte[] data,
							final int offset){
		final int ceil = data.length - want.length + 1;
		for (int idx = offset; idx < ceil; idx ++) {
			if (areValuesAt(want, data, idx)) {
				return idx;
			}
		}
		return -1;
	}

		/**
		  * Find the location of "want" in data. Returns -1 if
		  * not present.
		  *
		*/

	public static final int lastIndexOfIn(final byte want, 
							final byte[] data){
		for (int idx = data.length - 1; idx > -1; idx --) {
			if (want == data[idx]) {
				return idx;
			}
		}
		return -1;
	}

		/**
		  * Find the location of "want" in data. Returns -1 if
		  * not present.
		  *
		*/

	public static final int lastIndexOfIn(final byte[] want, 
							final byte[] data){
		for (int idx = data.length - want.length; 
				idx > -1; idx --) {
			if (areValuesAt(want, data, idx)) {
				return idx;
			}
		}
		return -1;
	}

		/**
		  * Return a portion of the array, much like String.subtring.
		  *
		*/

	public static final byte[] subArray(final byte[] data, 
					final int beginat, final int count) {
		byte[] answer = new byte[count];
		int srcidx = beginat;
		for (int destidx = 0; destidx < count; destidx ++) {
			answer[destidx] = data[srcidx];
			srcidx ++;
		}
		return answer;
	}

		/**
		  * Pretend that the bits in the value represent an
		  * unsigned integer, and return the value of the unsigned 
		  * integer.
		  * Example: if x = -1 the answer is 255,
		  * assuming that Java represents negative integers using
		  * twos complements.
		  *
		*/

	public static final int toUnsignedInt(byte x) {
		return 255 & x;
	}

}
